/*! \file block_info.cpp
 *	\brief 
 *
 *	created:	2009/11/20
 *	created:	20:11:2009   18:20
 *	filename: 	o:\main\libs\mem\impl\block_info.cpp
 *	file path:	o:\main\libs\mem\impl
 *	file base:	block_info
 *	file ext:	cpp
 *	author:		Vitalii Trubchaninov
 *				venngraydog@gmail.com
 */
 
#include "mem/stdafx.h"
#include "mem/impl/block_info.h"

#if TT_MEM_ENABLED && TT_MEM_PROFILING

#include <assert.h>
#include <sstream>

#include "routines.h"

namespace tt{
namespace mem{

namespace impl{

namespace {

	void print_aligned(std::stringstream& ss, std::size_t value)
	{
		if (value < 100)
		{
			ss << "0";
		}
		if (value < 10)
		{
			ss << "0";
		}
		ss << value;
	}

	void print_big_number(std::stringstream& ss, std::size_t value)
	{
		std::size_t _value = value;
		bool need_allign = false;
		if (_value > 1000000)
		{
			ss << _value / 1000000 << ",";
			_value %= 1000000;
			need_allign = true;
		}
		if (_value > 1000)
		{
			if(need_allign)
				print_aligned(ss, _value / 1000);
			else
				ss << _value / 1000;
			ss << ",";
			_value %= 1000;
			need_allign = true;
		}
		if(need_allign)
			print_aligned(ss, _value);
		else
			ss << _value;
	}

	void print_percent(std::stringstream& ss, std::size_t numerator, std::size_t denominator)
	{
		if (0 == numerator || 0 == denominator)
		{
			ss << " (-%)";
		}
		else
		{
			float percent = (float)numerator / (float)denominator * 100.f;
			ss << " (" << percent << "%)";
		}
	}
}

//////////////////////////////////////////////////////////////////////////
BlockInfo::BlockInfo( const char* name )
: m_parent(NULL)
, m_name(name)
, m_activation_count(0)
, m_total_data_dirty(false)
{

}

BlockInfo::~BlockInfo()
{

}

BlockInfo* BlockInfo::child( const char* name )
{
	assert(name);
	Childs::iterator it = m_childs.find(name);
	if(it == m_childs.end())
	{
#if TT_MEM_ENABLED
		impl::g_my_mem_function = true;
#endif
		BlockInfo* _child = new BlockInfo(name);
#if TT_MEM_ENABLED
		impl::g_my_mem_function = true;
#endif
		_child->m_parent = this;
		m_childs.insert(Childs::value_type(name, _child));
		return _child;
	}
	return it->second;
}

void BlockInfo::activate()
{
	++m_activation_count;
}

BlockInfo& BlockInfo::operator+=( std::size_t size )
{
	set_parent_total_data_dirty();
	++m_data.count;
	m_data.size += size;
	++m_total_data.count;
	m_total_data.size += size;
	return *this;
}

BlockInfo& BlockInfo::operator-=( std::size_t size )
{
	set_parent_total_data_dirty();
	--m_data.count;
	m_data.size -= size;
	--m_total_data.count;
	m_total_data.size -= size;
	return *this;
}

void BlockInfo::serialize( std::ofstream& os, std::size_t shift ) const
{
	std::stringstream ss;
	for(std::size_t i = shift; i > 0; --i)
		ss << " ";
 	ss << m_name;
	ss << " | N: " << m_activation_count;
	std::size_t _total_count = total_count();
	ss << " | C: ";
	print_big_number(ss, _total_count);
	if (m_parent)
	{
		print_percent(ss, m_data.count, m_parent->total_count());
	}
	ss << " | c: ";
	print_big_number(ss, m_data.count);
	print_percent(ss, m_data.count, _total_count);

	std::size_t _total_size = total_size();
	ss << " | S: ";
	print_big_number(ss, _total_size);
	if (m_parent)
	{
		print_percent(ss, m_data.size, m_parent->total_size());
	}
	ss << " | s: ";
	print_big_number(ss, m_data.size);
	print_percent(ss, m_data.size, _total_size);

	ss << std::endl;

	os << ss.str();
 
	for (Childs::const_iterator it = m_childs.begin(); it != m_childs.end(); ++it)
	{
		const BlockInfo* bi = it->second;
		bi->serialize(os, shift + 2);
	}
}

//////////////////////////////////////////////////////////////////////////
std::size_t BlockInfo::total_count() const
{
	if(m_total_data_dirty)
		validate_total_data();
	return m_total_data.count;
}

std::size_t BlockInfo::total_size() const
{
	if(m_total_data_dirty)
		validate_total_data();
	return m_total_data.size;
}

void BlockInfo::set_parent_total_data_dirty()
{
	for (BlockInfo* parent = m_parent; parent; parent = parent->m_parent)
	{
		parent->m_total_data_dirty = true;
	}
}

void BlockInfo::validate_total_data() const
{
	m_total_data.size = m_data.size;
	m_total_data.count = m_data.count;
	for (Childs::const_iterator it = m_childs.begin(); it != m_childs.end(); ++it)
	{
		const BlockInfo* bi = it->second;
		m_total_data.count += bi->total_count();
		m_total_data.size += bi->total_size();
	}
}

} //impl
} //mem
} //namespace tt

#endif //TT_MEM_ENABLED && TT_MEM_PROFILING

